home *** CD-ROM | disk | FTP | other *** search
- /* pop2d - Post Office Protocol server */
-
- static char rcsid[] = "@(#) $Header: pop2d.c,v 1.4 91/07/08 13:04:15 deyke Exp $";
-
- /*
-
- This server implements the POP2 protocol described in RFC937.
- It should work with any system derived from Unix 4.2/4.3 BSD.
- It adds a small feature to the standard protocol:
-
- The non-standard command "save" is supported. If a "save"
- command is issued, any message deleted from the user's mail
- spool file is saved in the "save" file (by default this is
- named by appending ".bak" to the spool file).
-
- To install this do the following:
-
- 1) Add a line to inetd.conf, as follows:
-
- pop2 stream tcp nowait root /etc/pop2d pop2d
-
- 2) Add a line to /etc/services, as follows
-
- pop2 109/tcp
-
- Dont forget to remake maps if YP is running
-
- */
-
- #define _HPUX_SOURCE
-
- #include <sys/types.h>
-
- #include <stdio.h>
-
- #include <ctype.h>
- #include <fcntl.h>
- #include <pwd.h>
- #include <signal.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <unistd.h>
-
- extern char *crypt();
- extern char *mktemp();
- extern struct passwd *getpwnam();
-
- #ifdef __STDC__
- #define __ARGS(x) x
- #else
- #define __ARGS(x) ()
- #endif
-
- #define null 0
- #define helo 1
- #define fold 2
- #define raed 3
- #define retr 4
- #define acks 5
- #define ackd 6
- #define nack 7
- #define quit 8
- #define save 9
- #define NKEYS 9
-
- static struct key_word {
- char *key;
- int val;
- int args;
- } keytab[] = {
- "null", null, 0,
- "helo", helo, 2,
- "fold", fold, 1,
- "read", raed, 1,
- "retr", retr, 0,
- "acks", acks, 0,
- "ackd", ackd, 0,
- "nack", nack, 0,
- "quit", quit, 0,
- "save", save, 1 /* Non standard */
- };
-
- #define AUTH 0
- #define MBOX 1
- #define ITEM 2
- #define NEXT 3
- #define DONE 4
- #define ERRO 5
-
- static int state_tab[4][NKEYS] = {
-
- /* helo fold read retr acks ackd nack quit save */
- /*-----------------------------------------------------------------*/
- /* AUTH: */ MBOX, ERRO, ERRO, ERRO, ERRO, ERRO, ERRO, DONE, ERRO,
- /* MBOX: */ ERRO, MBOX, ITEM, ERRO, ERRO, ERRO, ERRO, DONE, MBOX,
- /* ITEM: */ ERRO, MBOX, ITEM, NEXT, ERRO, ERRO, ERRO, DONE, MBOX,
- /* NEXT: */ ERRO, ERRO, ERRO, ERRO, ITEM, ITEM, ITEM, DONE, ERRO
-
- };
-
- /*
-
- State Diagram corresponding to the state transition table
- represented by the variable state_tab[][]
-
- |
- | helo
- |
- \|/
- -------------- quit -----------
- ------->| MBOX |-----------------> | DONE |
- fold | -------------- -----------
- or save | | | /|\ /|\
- --------- | | |
- | | |
- read | | fold or save |
- \|/ | |
- -------------- quit |
- ------->| ITEM |-------------------------
- read | -------------- |
- | | | /|\ |
- --------- | | ack(s/d) |
- retr | | |
- \|/ | |
- -------------- quit |
- | NEXT |-------------------------
- --------------
-
- --------------
- | ERRO |
- --------------
-
- */
-
- #define MAILDIR "/usr/mail/"
- #define MAXMSGS 1000
- #define SAVEFILE ".bak"
-
- struct message {
- long headp;
- int deleted;
- int lines;
- };
-
- static FILE *fsave;
- static FILE *ftemp;
- static char *mdir;
- static char line[1024];
- static char mailbox[1024];
- static char mailtmp[1024];
- static char myargv[4][1024];
- static char tmplate[] = "/tmp/popXXXXX";
- static int cur_msg;
- static int cur_msg_len;
- static int msg_cnt;
- static int myargc;
- static int nlines;
- static int nmsg;
- static int opened;
- static struct key_word key;
- static struct message msg[MAXMSGS+2];
- static struct passwd *pwd;
-
- static int parse __ARGS((void));
- static int check_user __ARGS((char *user, char *passwd));
- static int lexical __ARGS((void));
- static int whatkey __ARGS((char *s));
- static int openit __ARGS((void));
- static void closeit __ARGS((void));
- static int msglen __ARGS((int n));
- static void outmsg __ARGS((int n));
- static int my_gets __ARGS((char *s));
- static int openbk __ARGS((char *savefile));
- static int flock __ARGS((FILE *fp, int l_type));
-
- /*---------------------------------------------------------------------------*/
-
- int main(argc, argv)
- int argc;
- char **argv;
- {
- mdir = (argc >= 2) ? argv[1] : MAILDIR;
- gethostname(line, sizeof(line));
- printf("+ POP2 %s\r\n", line);
- while (parse() > 0) ;
- if (*mailtmp) unlink(mailtmp);
- return 0;
- }
-
- /*---------------------------------------------------------------------------*/
-
- /* Main parser - guides us through states and checks protocol compliance */
-
- static int parse()
- {
-
- char savebox[1024];
- int next_state;
- int token;
- static int cur_state;
-
- alarm(6 * 3600);
- token = lexical();
- if (token < 0) return (-1);
- next_state = state_tab[cur_state][token-1];
- switch (next_state) {
- case MBOX:
- switch (token) {
- case helo:
- if (check_user(myargv[1], myargv[2])) {
- printf("- Logon incorrect\r\n");
- return (-1);
- }
- strcpy(mailbox, mdir);
- strcat(mailbox, myargv[1]);
- msg_cnt = openit();
- printf("#%d messages in %s\r\n", msg_cnt, mailbox);
- break;
- case fold:
- strcpy(mailbox, myargv[1]);
- msg_cnt = openit();
- printf("#%d messages in %s\r\n", msg_cnt, mailbox);
- break;
- case save:
- if (myargc >= 1 && strlen(myargv[1]))
- strcpy(savebox, myargv[1]);
- else {
- strcpy(savebox, mailbox);
- strcat(savebox, SAVEFILE);
- }
- if (openbk(savebox))
- printf("+ Saving to %s\r\n", savebox);
- else
- printf("- Can't access file %s\r\n", savebox);
- break;
- }
- break;
- case ITEM:
- if (!opened) {
- printf("- No open mailbox\r\n");
- return (-1);
- }
- switch (token) {
- case raed:
- if (myargc) cur_msg = atoi(myargv[1]);
- if (cur_msg < 1) {
- printf("- Illegal message number\r\n");
- return (-1);
- }
- break;
- case ackd:
- msg[cur_msg].deleted = 1;
- case acks:
- cur_msg++;
- case nack:
- break;
- }
- if (cur_msg_len = msglen(cur_msg))
- printf("=%d characters in message %d\r\n", cur_msg_len, cur_msg);
- else
- printf("=0 no more messages\r\n");
- break;
- case NEXT:
- if (!cur_msg_len) {
- printf("- Zero length message\r\n");
- return (-1);
- }
- outmsg(cur_msg);
- break;
- case DONE:
- printf("+ OK, bye, bye\r\n");
- closeit();
- return 0;
- case ERRO:
- printf("- Syntax error\r\n");
- return (-1);
- }
- cur_state = next_state;
- return 1;
- }
-
- /*---------------------------------------------------------------------------*/
-
- /* Check userid and password */
-
- static int check_user(user, passwd)
- char *user, *passwd;
- {
- char *namep;
-
- pwd = getpwnam(user);
- if (!pwd) return (-1);
- namep = crypt(passwd, pwd->pw_passwd);
- if (strcmp(namep, pwd->pw_passwd)) return (-1);
- setgid(pwd->pw_gid);
- initgroups(user, (int) pwd->pw_gid);
- setuid(pwd->pw_uid);
- chdir(pwd->pw_dir);
- umask(077);
- return 0;
- }
-
- /*---------------------------------------------------------------------------*/
-
- /* Perform lexical analysis on incomming stuff */
-
- static int lexical()
- {
-
- char inline[1024];
- int i;
-
- for (i = 0; i < 3; i++) myargv[i][0] = '\0';
- myargc = -1;
- while (myargc < 0) {
- if (my_gets(inline) < 0) return (-1);
- myargc = sscanf(inline, "%s%s%s", myargv[0], myargv[1], myargv[2]);
- myargc--;
- }
- key = keytab[whatkey(myargv[0])];
- if (key.val == null) {
- printf("- Invalid command '%s'\r\n", myargv[0]);
- return (-1);
- }
- if (key.args && ((key.args - myargc) > 1)) {
- printf("- Not enough arguments for '%s'\r\n", myargv[0]);
- return (-1);
- }
- return key.val;
- }
-
- /*---------------------------------------------------------------------------*/
-
- /* Now determine which keyword we've got... */
-
- static int whatkey(s)
- char *s;
- {
- int i;
-
- for (i = 0; i < 4; i++) s[i] = tolower(s[i] & 0xff);
- for (i = NKEYS; i > 0; i--)
- if (!strncmp(keytab[i].key, s, 4)) return keytab[i].val;
- return null;
- }
-
- /*---------------------------------------------------------------------------*/
-
- /* Open the specified mailbox */
-
- static int openit()
- {
-
- FILE * fmail;
- struct stat statb;
-
- if (opened) closeit();
- nmsg = 0;
- nlines = 0;
- strcpy(mailtmp, tmplate);
- mktemp(mailtmp);
- unlink(mailtmp);
- if (!(ftemp = fopen(mailtmp, "w+"))) return 0;
- if (!(fmail = fopen(mailbox, "r+"))) {
- fclose(ftemp);
- unlink(mailtmp);
- return 0;
- }
- flock(fmail, F_WRLCK);
- if (fstat(fileno(fmail), &statb) || statb.st_size == 0) {
- fclose(ftemp);
- unlink(mailtmp);
- fclose(fmail);
- return 0;
- }
- while (fgets(line, sizeof(line), fmail)) {
- if (strncmp("From ", line, 5) == 0) {
- msg[nmsg++].lines = nlines;
- nlines = 0;
- msg[nmsg].headp = ftell(fmail) - strlen(line);
- } else
- nlines++;
- fputs(line, ftemp);
- }
- msg[nmsg].lines = nlines;
- msg[nmsg+1].headp = ftell(fmail);
- fclose(fmail);
- cur_msg = 1;
- opened = 1;
- return nmsg;
- }
-
- /*---------------------------------------------------------------------------*/
-
- static void closeit()
- {
-
- FILE * fmail;
- int changed;
- int i;
- int j;
- struct stat statb;
-
- if (!opened) return;
- changed = 0;
- for (i = 1; i <= nmsg; i++)
- if (msg[i].deleted) {
- changed = 1;
- break;
- }
- if (changed) {
- signal(SIGINT, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- if (!(fmail = fopen(mailbox, "r+"))) return;
- flock(fmail, F_WRLCK);
- fstat(fileno(fmail), &statb);
- if (statb.st_size != msg[nmsg+1].headp) {
- fseek(fmail, msg[nmsg+1].headp, SEEK_SET);
- fseek(ftemp, msg[nmsg+1].headp, SEEK_SET);
- nlines = 0;
- while (fgets(line, sizeof(line), fmail)) {
- nlines++;
- fputs(line, ftemp);
- }
- nmsg++;
- msg[nmsg].lines = nlines - 1;
- msg[nmsg+1].headp = ftell(ftemp);
- }
- #if 0
- ftruncate(fileno(fmail), 0L);
- #else
- close(creat(mailbox, 0660));
- #endif
- rewind(fmail);
- for (i = 1; i <= nmsg; i++) {
- if (!msg[i].deleted || fsave) {
- fseek(ftemp, msg[i].headp, SEEK_SET);
- for (j = 0; j <= msg[i].lines; j++) {
- fgets(line, sizeof(line), ftemp);
- fputs(line, msg[i].deleted ? fsave : fmail);
- }
- }
- }
- fclose(fmail);
- }
- fclose(ftemp);
- unlink(mailtmp);
- opened = 0;
- }
-
- /*---------------------------------------------------------------------------*/
-
- /* Compute a message's length. <lf> counts as <cr><lf> */
-
- static int msglen(n)
- {
- struct message *m;
-
- if (n > nmsg || msg[n].deleted) return 0;
- m = msg + n;
- fseek(ftemp, m->headp, SEEK_SET);
- fgets(line, sizeof(line), ftemp);
- return (msg[n+1].headp - m->headp) - strlen(line) + m->lines;
- }
-
- /*---------------------------------------------------------------------------*/
-
- /*
- * Output msg to primary, convert to net standard ascii.
- * We are already positioned at the first line.
- */
-
- static void outmsg(n)
- int n;
- {
- int i;
-
- for (i = msg[n].lines; i > 0; i--) {
- fgets(line, sizeof(line), ftemp);
- line[strlen(line)-1] = '\0';
- printf("%s\r\n", line);
- }
- }
-
- /*---------------------------------------------------------------------------*/
-
- /* Read an entire line from the network */
-
- static int my_gets(s)
- char *s;
- {
- int c;
-
- fflush(stdout);
- while ((c = getchar()) != '\n') {
- if (ferror(stdin) || feof(stdin)) return (-1);
- if (c != '\r') *s++ = c;
- }
- *s = '\0';
- return 0;
- }
-
- /*---------------------------------------------------------------------------*/
-
- /* Open a backup file for deleted messages */
-
- static int openbk(savefile)
- char *savefile;
- {
- if (fsave) fclose(fsave);
- if (fsave = fopen(savefile, "a")) return 1;
- return 0;
- }
-
- /*---------------------------------------------------------------------------*/
-
- static int flock(fp, l_type)
- FILE *fp;
- int l_type;
- {
- struct flock flk;
-
- flk.l_whence = 0;
- flk.l_len = 0;
- flk.l_type = l_type;
- return fcntl(fileno(fp), F_SETLKW, &flk);
- }
-
-